package xml_parser


import (
	"fmt"
	"github.com/antchfx/xmlquery"
	"io/ioutil"
	"os"
	"strings"
)

type Mapper struct {
	EntityMap map[string]Entity `json:"entity_map"`				//实体映射
}

type Entity struct {
	Package  		string 					`json:"package"`		//包名
	MethodMap 		map[string]Method 		`json:"method_map"`		//方法映射
}

type Method struct {
	MethodType              string `json:"method_type"`			//方法类型
	MethodName 				string `json:"method_name"`			//方法名称
	ParameterType 			string `json:"parameter_type"`		//参数类型
	ResultType              string `json:"result_type"`			//结果类型
	InnerSql                string `json:"inner_sql"`			//内部sql
}

var M Mapper

/*
	todo
	1,按照 insert delete update select 存储方法
	2,后续考虑升级sync.Map
	3,加入缓存，考虑把方法数据存储到第三方插件
	4,热更新方法
*/
func ParseXml(path string){
	//遍历path路径
	fileList, err := ioutil.ReadDir(path)
	if err!=nil{
		fmt.Println("遍历文件夹失败",err)
		return
	}
	M = Mapper{EntityMap: make(map[string]Entity)}

	for _,file:=range fileList {
		fileName:=file.Name()

		file, err2 := os.OpenFile(fmt.Sprintf("%v/%v",path,fileName), os.O_RDWR, 0777)
		if err2 != nil {
			fmt.Println(err2)
			return
		}
		defer file.Close()

		doc, err := xmlquery.Parse(file)
		if err != nil {
			fmt.Println(err)
			return
		}
		root, _ := xmlquery.Query(doc, "//mapper")

		var pg string
		for _, attr := range root.Attr {
			pg = attr.Value
			continue
		}

		entity := Entity{
			Package:   pg,
			MethodMap: make(map[string]Method),
		}

		m, _ := xmlquery.Query(doc, "//mapper")

		//查询
		selectElements := m.SelectElements("select")
		for _, e := range selectElements {
			method := Method{}
			for _, attr := range e.Attr {
				switch strings.ToLower(strings.TrimSpace(attr.Name.Local)) {
				case "method":
					method.MethodName = attr.Value
				case "parametertype":
					method.ParameterType = attr.Value
				case "resulttype":
					method.ResultType = attr.Value
				}
			}
			method.InnerSql = e.InnerText()
			entity.MethodMap[method.MethodName] = method
		}

		//插入
		insertElements := m.SelectElements("insert")
		for _, e := range insertElements {
			method := Method{}
			for _, attr := range e.Attr {
				switch strings.ToLower(strings.TrimSpace(attr.Name.Local)) {
				case "method":
					method.MethodName = attr.Value
				case "parametertype":
					method.ParameterType = attr.Value
				case "resulttype":
					method.ResultType = attr.Value
				}
			}
			method.InnerSql = e.InnerText()
			entity.MethodMap[method.MethodName] = method
		}

		M.EntityMap[pg] = entity
	}
}